/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.merak.core;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.merak.core.configuration.Configuration;
import org.merak.core.configuration.XMLConfigurator;
import org.merak.core.configuration.plugin.PluginSet;
import org.merak.core.model.IShutdownHook;
import org.merak.core.model.parameter.Property;

public final class Application {

	//~ Static: Auxiliary Managers ////////////////////////////////////////////////
	//****************************************************************************
	public static final Paths    paths = new Paths();
	public static final IO       io    = new IO();
	public static final Web      web   = new Web();
	public static final Database database;

	//~ Static: Attributes ///////////////////////////////////////////////////////
	//****************************************************************************
	private static boolean             isWebApp      = Initializer.getIsWebApp();
	private static Configuration       configuration = null;
	private static List<IShutdownHook> shutdownList  = new LinkedList<IShutdownHook>();
	private static Logger              logger        = Logger.getLogger("Core");

	//~ Static Constructor ///////////////////////////////////////////////////////
	//****************************************************************************
	static {

		// Start by resolving paths of this application
		Application.paths.init(Initializer.getDocBase(),isWebApp);

		/* Now, lets prioritize the initialization of the Logging System,
		 * in this case Log4j from "ApplicationData/Configurations/log4j.xml" */
		Initializer.initLog4j(
				Application.paths.configuration.getFile("log4j.xml")
		);

		/* Paths resolved, logging working... now load MerakCore's configurations
		 * centralized in the file "ApplicationData/Application.xml" */
		Application.configuration = new XMLConfigurator().load(
				Application.paths.applicationData.getFile("Application.xml")
		);

		// Automatically set Java Properties found in Application.xml
		for ( Property p : Application.configuration.getSystemProperties() ) {
				System.setProperty(p.getName(), p.getValue());
		}

		// Install a central shutdown hook
		Runtime.getRuntime().addShutdownHook( new Thread() {
			@Override public void run() {
				String msg = "SIGTERM received. Shutting down NOW!";
				if (logger!=null) logger.info(msg); else System.out.println(msg);
				Application.shutdown();
			}}
		);

		// Log some initialization info
		Application.logger.info(
			"\"" + Application.getName() +
			"\" is running as " +
			(Application.isWebApp ? "Web Application" : "Desktop Application")
		);
		Application.logger.info( "DocBase is "   + Application.paths.docBase );
		Application.logger.info( "DataDir is "   + Application.paths.applicationData );

		// Clear temporary directory
		if (paths.temporary.getFile().exists()) {
			logger.info("Cleaning " + paths.temporary);
			for (File file : paths.temporary.listFiles()) {
				file.delete();
			}
		}

		// Initialize the database manager
		database = new Database();

	}

	//~ Methods //////////////////////////////////////////////////////////////////
	//****************************************************************************
	public static String getName() {

		return (Application.configuration==null)
				? "Unnamed"
				: Application.configuration.getName();

	}
	//****************************************************************************
	public static String getDescription() {

		return (Application.configuration==null)
				? "Unavailable"
				: Application.configuration.getDescription();

	}
	//****************************************************************************
	public static boolean isWebApplication() {
		return Application.isWebApp;
	}
	//****************************************************************************
	public static Logger getLogger() {
		return logger;
	}
	//****************************************************************************
	public static Logger createLogFile(String name,String pattern,boolean append)
	{

		Logger logger = Logger.getLogger(name);
		Layout layout = new PatternLayout(pattern);
		String path   = paths.log.getPath(name+".log");

		try {
			logger.addAppender(new FileAppender(layout,path,append));
		}
		catch (IOException e) {throw new RuntimeException(
			"Cannot create log file '" + path + "'",e
		);}
		return logger;

	}
	//****************************************************************************
	public static String getProperty(String name) {

		Property property = Application.configuration.getProperty(name);
		return  ( property != null )
				? property.getValue()
				: null;

	}
	//****************************************************************************
	public static Collection<Property> getSystemProperties() {
		return Application.configuration.getSystemProperties();
	}
	//****************************************************************************
	public static Collection<Property> getProperties() {
		return Application.configuration.getProperties();
	}
	//****************************************************************************
	public static PluginSet getPluginSet(String spiPackage) {
		return Application.configuration.getServiceSet(spiPackage);
	}
	//****************************************************************************
	public static Configuration getConfiguration() {
		return Application.configuration;
	}
	//****************************************************************************
	public static void addShutdownHook(IShutdownHook hook) {
		shutdownList.add(hook);
	}
	//****************************************************************************
	public static synchronized void shutdown() {

		if (configuration != null) {
			// Shutdown
			Application.logger.info("\""+Application.getName()+"\" has started Shutdown...");
			for (IShutdownHook hook : shutdownList) {
				hook.shutdown();
			}
			Application.logger.info("\""+Application.getName()+"\" has finished Shutdown.");
			// Reset Attributes
			 configuration = null;
		}

	}
	//****************************************************************************
}

